package com.vy.stl.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.UUID;

/**
 * JWT的工具类
 * 对应 0.12.x版本
 */
public class JWTUtil {

    //定义JWT有效期
    public static final Long JWT_TTL = 30 * 60 * 1000L;// 60 * 60 *1000  30分钟

    //定义JWT签名密钥 至少32位
    public static final String JWT_KEY = "situ_20240508situ_20240508situ_20240508situ_20240508situ_20240508";

    //生成UUID（去横线），作为JWT唯一标识（JTI）
    public static String getUUID(){
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 通过subject, null, UUID生成JWT令牌
     * @param subject token中要存放的数据（json格式）
     * @return 生成的JWT令牌
     */
    public static String createJWT(String subject) {
        //调用getJwtBuilder方法构建JWT，使用默认有效期和自动生成的UUID作为ID
        JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
        //压缩为最终的JWT字符串
        return builder.compact();
    }

    /**
     * subject, ttlMillis, UUID生成JWT令牌（可指定有效期）
     * @param subject
     * @param ttlMillis 令牌超时时间（毫秒）
     * @return 生成的JWT令牌
     */
    public static String createJWT(String subject, Long ttlMillis) {
        //调用getJwtBuilder方法，使用指定的有效期和自动生成的UUID
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());
        return builder.compact();
    }

    /**
     * 创建自定义ID的JWT令牌
     * @param id 自定义的令牌ID（JTI）
     * @param subject
     * @param ttlMillis
     * @return 生成的JWT令牌
     */
    public static String createJWT(String id, String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);
        return builder.compact();
    }

    /**
     * 构建JWT的核心方法
     * @param subject 令牌中存储的数据
     * @param ttlMillis 有效期（毫秒，为null则使用默认值）
     * @param uuid 令牌的唯一标识
     * @return JwtBuilder对象，用于构建最终令牌
     */
    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
        //指定签名算法为HS256
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        //生成签名密钥
        SecretKey secretKey = generalKey();
        //当前时间戳（毫秒）
        long nowMillis = System.currentTimeMillis();
        //当前时间
        Date now = new Date(nowMillis);
        //如果未指定有效期，使用默认值
        if(ttlMillis==null){
            ttlMillis= JWTUtil.JWT_TTL;
        }
        //计算过期时间戳
        long expMillis = nowMillis + ttlMillis;
        //过期时间
        Date expDate = new Date(expMillis);
        //构建JWT的核心信息
        return Jwts.builder()
                .setId(uuid)            //设置唯一的ID
                .setSubject(subject)    //设置主题  可以是JSON数据
                .setIssuer("sg")        //设置签发者
                .setIssuedAt(now)       //设置签发时间
                .signWith(signatureAlgorithm, secretKey) //使用指定算法和密钥签名
                .setExpiration(expDate);//设置过期时间
    }

    /**
     * 生成加密后的签名密钥（基于JWT_KEY）
     * @return 符合SH256算法要求的SecretKey对象
     */
    public static SecretKey generalKey() {
        //对密钥进行Base64解密
        byte[] encodedKey = Base64.decodeBase64(JWTUtil.JWT_KEY);
        //根据解密后的字节数组生成HS256算法的密钥
        return new SecretKeySpec(encodedKey, 0, encodedKey.length, "HmacSHA256");
    }

    /**
     * 解析JWT令牌，获取其中的声明（Claims）
     * @param jwt 待解析的JWT字符串
     * @return 包含令牌信息的Claims对象
     * @throws Exception 解析失败时抛出异常（如令牌无效、过期等）
     */
    public static Claims parseJWT(String jwt) throws Exception {
        //获取签名密钥
        SecretKey secretKey = generalKey();
        //解析JWT并验证签名
        return Jwts.parser()
                //设置验证用的密钥
                .verifyWith(secretKey)
                //构建解析器
                .build()
                //解析令牌
                .parseSignedClaims(jwt)
                //获取 payload 中的声明信息
                .getPayload();
    }

    //主方法，用于测试JWT的生成和解析
    public static void main(String[] args) throws Exception {
        //加密：生成JWT令牌
//        String jwt = createJWT("15377668899");
//        System.out.println(jwt);
        //解密：解析指定的JWT令牌
        Claims claims = parseJWT("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJlMmVjNDc5MTI1MGM0M2VkOWE2ODA2ZDNlMzcyOTYzNSIsInN1YiI6IjE1Mzc3NjY4ODk5IiwiaXNzIjoic2ciLCJpYXQiOjE3NTc1NTQ2NTQsImV4cCI6MTc1NzU1NjQ1NH0.fT2O_oD0YjmKNLdVxd_4a-tyl_Y7PW6iXpS3V80_zxA");
                //获取主题信息
        String subject = claims.getSubject();
//        打印解析出的主题
        System.out.println(subject);
    }
}